package per.turtle.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import per.turtle.common.core.constant.CacheConstants;
import per.turtle.common.core.exception.CustomException;
import per.turtle.common.core.web.dto.TreeSelect;
import per.turtle.system.entity.SysDept;
import per.turtle.system.entity.SysUser;
import per.turtle.system.mapper.SysDeptMapper;
import per.turtle.system.mapper.SysRoleDeptMapper;
import per.turtle.system.mapper.SysUserMapper;
import per.turtle.system.service.ISysDeptService;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 部门管理 服务层实现
 *
 * @author turtle
 */
@RequiredArgsConstructor
@Service
public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> implements ISysDeptService {

    private final SysUserMapper userMapper;

    private final SysRoleDeptMapper roleDeptMapper;

    @Override
    public List<TreeSelect> buildDeptTreeSelect(List<SysDept> depts) {
        List<SysDept> deptTrees = buildDeptTree(depts);
        return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
    }

    @Override
    public boolean checkDeptExistUser(String deptId) {
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(SysUser::getDeptId, deptId);
        Long result = userMapper.selectCount(wrapper);
        return result > 0;
    }

    @Override
    public boolean checkDeptNameUnique(SysDept dept) {
        QueryWrapper<SysDept> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(StrUtil.isNotBlank(dept.getDeptName()), SysDept::getDeptName, dept.getDeptName())
               .ne(dept.getDeptId() != null, SysDept::getDeptId, dept.getDeptId());
        List<SysDept> infos = baseMapper.selectList(wrapper);
        return infos.isEmpty();
    }

    @Override
    public int deleteDeptById(String deptId) {
        return baseMapper.deleteById(deptId);
    }

    @Override
    @Cacheable(value = CacheConstants.SYS_DEPT_KEY, key = "#deptId")
    public SysDept getDeptById(String deptId) {
        return baseMapper.selectById(deptId);
    }

    @Override
    public List<String> getDeptIdsWithChildByDeptId(String deptId) {
        return baseMapper.selectDeptIdsWithChildByDeptId(deptId);
    }

    @Override
    public boolean hasChildByDeptId(String deptId) {
        QueryWrapper<SysDept> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(SysDept::getParentId, deptId);
        return baseMapper.selectCount(wrapper) > 0;
    }

    @Override
    public Long hasNormalChildrenDeptById(String deptId) {
        QueryWrapper<SysDept> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(SysDept::getIsDisabled, true).apply(BeanUtil.isNotEmpty(deptId), "FIND_IN_SET ('" + deptId + "', ancestors)");
        return baseMapper.selectCount(wrapper);
    }

    @Override
    public int insertDept(SysDept dept) {
        // 有父节点
        if (dept.getParentId() != null) {
            // 如果父节点被停用,则不允许新增子节点
            SysDept fatherDept = baseMapper.selectById(dept.getParentId());
            if (fatherDept.getIsDisabled()) {
                throw new CustomException("部门停用，不允许新增");
            }
            dept.setAncestors((StrUtil.isNotBlank(fatherDept.getAncestors()) ? fatherDept.getAncestors() + StrUtil.COMMA : "") + dept.getParentId());
        }

        return baseMapper.insert(dept);
    }

    @Override
    public SysDept selectDeptById(String deptId) {
        return baseMapper.selectById(deptId);
    }

    @Override
    public List<String> selectDeptIdsByRole(String roleId) {
        return roleDeptMapper.selectDeptIdsByRole(roleId);
    }

    @Override
    public List<SysDept> selectDeptList(SysDept dept) {
        return baseMapper.selectDeptList(dept);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateDept(SysDept dept) {
        // 更新父级列表和相关子级和数据
        SysDept newParentDept = baseMapper.selectById(dept.getParentId());
        SysDept oldDept = baseMapper.selectById(dept.getDeptId());
        if (BeanUtil.isNotEmpty(newParentDept) && BeanUtil.isNotEmpty(oldDept)) {
            // 该部门新的父级列表
            List<String> newAncestors = StrUtil.split(newParentDept.getAncestors(), StrUtil.C_COMMA);
            newAncestors.add(newParentDept.getDeptId());
            // 老的
            List<String> oldAncestors = StrUtil.split(oldDept.getAncestors(), StrUtil.C_COMMA);
            // 设置父级列表
            dept.setAncestors(StrUtil.sub(newAncestors.toString(), 1, -1));
            // 更新相关子级的父级列表
            this.updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);
        }
        int result = baseMapper.updateById(dept);

        if (!dept.getIsDisabled()) {
            // 如果该部门是启用状态，则启用该部门的所有上级部门（理论上不应该存在该情况）
            updateParentDeptStatusNormal(dept);
        }
        return result;
    }

    private List<SysDept> buildDeptTree(List<SysDept> depts) {
        List<SysDept> returnList = new ArrayList<>();
        List<String> tempList = new ArrayList<>();
        for (SysDept dept : depts) {
            tempList.add(dept.getDeptId());
        }
        for (SysDept dept : depts) {
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(dept.getParentId())) {
                recursionFn(depts, dept);
                returnList.add(dept);
            }
        }
        if (returnList.isEmpty()) {
            returnList = depts;
        }
        return returnList;
    }

    /**
     * 得到子节点列表
     */
    private List<SysDept> getChildList(List<SysDept> list, SysDept t) {
        List<SysDept> tList = new ArrayList<>();
        for (SysDept n : list) {
            if (BeanUtil.isNotEmpty(n.getParentId()) && n.getParentId().equals(t.getDeptId())) {
                tList.add(n);
            }
        }
        return tList;
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<SysDept> list, SysDept t) {
        return getChildList(list, t).size() > 0;
    }

    /**
     * 递归列表
     */
    private void recursionFn(List<SysDept> list, SysDept t) {
        // 得到子节点列表
        List<SysDept> childList = getChildList(list, t);
        t.setChildren(childList);
        for (SysDept tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }

    /**
     * 修改子元素关系
     *
     * @param deptId       被修改的部门ID
     * @param newAncestors 新的父ID集合
     * @param oldAncestors 旧的父ID集合
     */
    private void updateDeptChildren(String deptId, List<String> newAncestors, List<String> oldAncestors) {
        QueryWrapper<SysDept> wrapper = new QueryWrapper<>();
        wrapper.lambda().apply(BeanUtil.isNotEmpty(deptId), "FIND_IN_SET ('" + deptId + "', ancestors)");
        List<SysDept> children = baseMapper.selectList(wrapper);
        for (SysDept child : children) {
            List<String> childAncestors = StrUtil.split(child.getAncestors(), StrUtil.C_COMMA);
            childAncestors.removeAll(oldAncestors);
            childAncestors.addAll(newAncestors);
            // 去重，排序
            child.setAncestors(
                    StrUtil.sub(childAncestors.stream().distinct().sorted(Comparator.comparingLong(Long::parseLong)).collect(Collectors.toList()).toString(), 1,
                                -1));
            baseMapper.updateById(child);
        }
    }

    /**
     * 修改该部门的父级部门状态
     *
     * @param dept 当前部门
     */
    private void updateParentDeptStatusNormal(SysDept dept) {
        String ancestors = dept.getAncestors();
        Set<String> deptIds = ListUtil.of(Convert.toStrArray(ancestors)).stream().map(String::trim).filter(StrUtil::isNotEmpty).collect(Collectors.toSet());
        SysDept changeStatus = new SysDept();
        changeStatus.setIsDisabled(false);

        QueryWrapper<SysDept> wrapper = new QueryWrapper<>();
        wrapper.lambda().in(deptIds.size() > 0, SysDept::getDeptId, deptIds);
        baseMapper.update(changeStatus, wrapper);
    }

}
